#include "common/chassis_serial.h"

using namespace alive::chassis_serial;

ChassisSerial::ChassisSerial(const std::string serialName, const int rate):
    serial_name_(serialName),
    serial_rate_(rate)
{
    recv_flag_ = false;
    process_flag_ = false;
    recv_thr_ = nullptr;
    process_thr_ = nullptr;
    printf("dev:%s\n",serial_name_.data());
}
ChassisSerial::~ChassisSerial()
{
    printf("========ChassisSerial Destructor========\n");
    stopRecv();
    stopProcess();
    buf_.clear();
    serial_.close();
    printf("========ChassisSerial Destructor end========\n");
}


bool ChassisSerial::initSerial()
{
    try {
        //设置串口属性，并打开串口
        serial_.setPort(serial_name_);
        serial_.setBaudrate(serial_rate_);
        serial_.setFlowcontrol(serial::flowcontrol_t::flowcontrol_none);
        serial_.setParity(serial::parity_t::parity_none);
        serial_.setStopbits(serial::stopbits_t::stopbits_one);
        serial_.setBytesize(serial::bytesize_t::eightbits);
        serial::Timeout timeout = serial::Timeout::simpleTimeout(1000);
        serial_.setTimeout(timeout);
        serial_.open();
    } catch (serial::IOException &e) {
        std::cout << "open serial ultra" << " ERROR: " << e.what() << std::endl;
        return false;
    }

    //检测串口是否已经打开，并给出提示信息data
    if (serial_.isOpen()) {
        std::cout << "chassis serial port initialized success" << std::endl;
        return true;
    }
    
    return false;
}

int ChassisSerial::sendData(u_int8_t* data, size_t len)
{
    if(serial_.isOpen()){
        size_t ret = serial_.write(data, len);
        if(ret >= len){
            return 1;
        }else{
            std::cout << "chassis serial port write fail!!!" << std::endl;
            return 0;
        }
    }else{
        std::cout << "chassis serial port isn't open" << std::endl;
        return -1;
    }
}

void ChassisSerial::recieveData()
{
    buf_.clear();
    // buf_.resize(2048);
    uint8_t  buf[256] = {0};

    while(recv_flag_){
        try
        {
            /* code */
            if(!process_flag_){
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            }
            if(serial_.isOpen()){
                if(serial_.waitReadable()){
                    
                    size_t ret;
                    ret = serial_.read(buf, sizeof(buf));
                    if(ret >0){
                        if((buf_.size() + ret) < 2048) 
                        {
                            printf("read  ret = %ld.\n", ret);
                            std::unique_lock<std::mutex> lck(buf_mutex_);
                            buf_.insert(buf_.end(), buf, buf+ret);
                            lck.unlock();
                            condition_var_.notify_all();
                        }else{
                            printf("buf too large .\n");
                        }
                        
                    }else{
                        printf("read waring ret = %ld.\n", ret);
                    }
                }
            }else{
                initSerial();
                printf("reopen serial port.\n");
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
      
    }

}

void ChassisSerial::processData()
{
    while (process_flag_)
    {
        try{
            /* code */
            std::unique_lock<std::mutex> lck(buf_mutex_);
            condition_var_.wait(lck, [this]{return !buf_.empty();});
            if(process_call_){
                process_call_(buf_);
            }else{
                printf("process_call_ isn't register.\n");
            }
            lck.unlock();
        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
        

    }
    
}

void ChassisSerial::starRecv()
{
    printf("=========================\n");
    printf("serial start receive info!!!\n");
    printf("=========================\n");
    recv_flag_ = true;
    recv_thr_.reset(new std::thread(std::bind(&ChassisSerial::recieveData, this)));
}

void ChassisSerial::starProcess()
{
    printf("=========================\n");
    printf("serial start process data!!!\n");
    printf("=========================\n");
    process_flag_ = true;
    process_thr_.reset(new std::thread(std::bind(&ChassisSerial::processData, this)));
}

void ChassisSerial::stopRecv()
{
    recv_flag_ = false;
    if(recv_thr_ && recv_thr_->joinable()){

        printf("=========================\n");
        printf("serial stop receive info!!!\n");
        printf("=========================\n");
        recv_thr_->join();
        
    }
    recv_thr_ = nullptr;
}

void ChassisSerial::stopProcess()
{
    process_flag_ = false;
    if(process_thr_ && process_thr_->joinable()){
        printf("=========================\n");
        printf("serial stop process data!!!\n");
        printf("=========================\n");
        process_thr_->join();
    }
    process_thr_ = nullptr;
}
